package com.ygqh.baby.service.impl;

import com.ygqh.baby.ao.DataStatus;
import com.ygqh.baby.ao.Message;
import com.ygqh.baby.ao.QueryInfo;
import com.ygqh.baby.ao.ResultSet;
import com.ygqh.baby.mapper.BiSupplierOrderDayMapper;
import com.ygqh.baby.po.BiSupplierOrderDay;
import com.ygqh.baby.po.BiSupplierOrderDayExample;
import com.ygqh.baby.po.YgOrder;
import com.ygqh.baby.po.YgOrderDetail;
import com.ygqh.baby.service.BiSupplierOrderDayService;
import com.ygqh.baby.service.YgOrderService;
import com.ygqh.baby.template.AbstractSplitListTemplate;
import com.ygqh.baby.utils.DateConvertUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Ss
 */
@Service
public class BiSupplierOrderDayServiceImpl implements BiSupplierOrderDayService {

	private final BigDecimal ZERO = new BigDecimal("0.00");

	@Autowired
	private BiSupplierOrderDayMapper biSupplierOrderDayMapper;
	@Autowired
	private YgOrderService ygOrderService;

	@Value("${yiigoo.supplier.id}")
	private Long ygSupplierId;

	@Override
	public List<BiSupplierOrderDay> find() {
		BiSupplierOrderDayExample example = new BiSupplierOrderDayExample();
		example.createCriteria().andStatusEqualTo(DataStatus.Valid.name());
		return biSupplierOrderDayMapper.selectByExample(example);
	}

	@Override
	public int findCount() {
		BiSupplierOrderDayExample example = new BiSupplierOrderDayExample();
		example.createCriteria().andStatusEqualTo(DataStatus.Valid.name());
		return biSupplierOrderDayMapper.countByExample(example);
	}

	@Override
	public BiSupplierOrderDay findById(Long id) {
		return biSupplierOrderDayMapper.selectByPrimaryKey(id);
	}

	@Override
	public int save(BiSupplierOrderDay biSupplierOrderDay) {
		return biSupplierOrderDayMapper.insertSelective(biSupplierOrderDay);
	}

	@Override
	public int update(BiSupplierOrderDay biSupplierOrderDay) {
		return biSupplierOrderDayMapper.updateByPrimaryKeySelective(biSupplierOrderDay);
	}

	@Override
	public ResultSet<BiSupplierOrderDay> search(QueryInfo queryInfo, String q, Date startDate, Date endDate, Long supplierId) {
		List<BiSupplierOrderDay> list = this.findList(queryInfo, q, startDate, endDate, supplierId);
		int count = biSupplierOrderDayMapper.countSuper(q, startDate, endDate, supplierId);
		return new ResultSet<>(count, list);
	}

	@Override
	public List<BiSupplierOrderDay> findList(QueryInfo queryInfo, String q, Date startDate, Date endDate,
											 Long supplierId) {
		List<BiSupplierOrderDay> list = biSupplierOrderDayMapper.selectSuper(queryInfo, q, startDate, endDate, supplierId);
		doGrossMargin(list);
		return list;
	}

	@Override
	public int deleteSoft(Long[] ids) {
		Assert.notEmpty(ids);
		BiSupplierOrderDayExample example = new BiSupplierOrderDayExample();
		example.createCriteria().andIdIn(Arrays.asList(ids));
		BiSupplierOrderDay record = new BiSupplierOrderDay();
		record.setStatus(DataStatus.Delete);
		return biSupplierOrderDayMapper.updateByExampleSelective(record, example);
	}

	@Override
	public int deleteSoft(Long id) {
		return this.deleteSoft(new Long[]{id});
	}

	@Override
	public int saveOrUpdate(BiSupplierOrderDay biSupplierOrderDay) {
		int r;
		if (biSupplierOrderDay.getId() != null) {
			r = this.update(biSupplierOrderDay);
		} else {
			r = this.save(biSupplierOrderDay);
		}
		return r;
	}

	@Override
	public int saveBatch(List<BiSupplierOrderDay> biSupplierOrderDayList) {
		return new AbstractSplitListTemplate<BiSupplierOrderDay>(biSupplierOrderDayList) {
			@Override
			public int execute(List<BiSupplierOrderDay> recordList) {
				return biSupplierOrderDayMapper.insertBatch(recordList);
			}
		}.split();
	}

	@Override
	public List<BiSupplierOrderDay> supplierOrderReportWithSplitYG(Date startDate, Date endDate) {
		Date currentDate = DateConvertUtils.getDateStart(new Date());
		List<BiSupplierOrderDay> list = new ArrayList<>();

		if (startDate.before(currentDate)) {
			// 包含今天前的数据
			List<BiSupplierOrderDay> historyList = biSupplierOrderDayMapper.supplierOrderReportWithSplitYG(startDate, endDate);
			if (CollectionUtils.isNotEmpty(historyList)) {
				list.addAll(historyList);
			}
		}
		if (endDate.after(currentDate)) {
			// 统计今天的数据
			List<BiSupplierOrderDay> currentList = this.statisticsSupplierOrderByTimeV2(currentDate, endDate,
					false, false);
			doCurrentDataToList(list, currentList);
		}
		if (CollectionUtils.isEmpty(list)) {
			return new ArrayList<>();
		}
		doGrossMargin(list);
		return list;
	}

	private void doCurrentDataToList(List<BiSupplierOrderDay> list, List<BiSupplierOrderDay> currentList) {
		if (CollectionUtils.isEmpty(currentList)) {
			return;
		}
		BiSupplierOrderDay ygDay = null;
		BiSupplierOrderDay thirdDay = null;
		BigDecimal zero = new BigDecimal("0.00");

		Long totalOrderCount = 0L;
		BigDecimal totalOrderPrice = zero;
		Long totalUserCount = 0L;
		Long payOrderCount = 0L;
		BigDecimal payOrderPrice = zero;
		Long payUserCount = 0L;
		BigDecimal totalCostPrice = zero;

		boolean hasThirdDay = false;
		for (BiSupplierOrderDay o : currentList) {
			if (o.getSupplierId().compareTo(1L) == 0) {
				ygDay = o;
			} else {
				hasThirdDay = true;
				totalOrderCount += o.getTotalOrderCount();
				totalOrderPrice = totalOrderPrice.add(o.getTotalOrderPrice());
				totalUserCount += o.getTotalUserCount();
				payOrderCount += o.getPayOrderCount();
				payOrderPrice = payOrderPrice.add(o.getPayOrderPrice());
				payUserCount += o.getPayUserCount();
				totalCostPrice = totalCostPrice.add(o.getTotalCostPrice());
			}
		}
		if (hasThirdDay) {
			thirdDay = new BiSupplierOrderDay(null, totalOrderCount, totalOrderPrice, totalUserCount, payOrderCount, payOrderPrice, payUserCount,
					totalCostPrice, null, 0L, "外部品牌");
		}
		if (CollectionUtils.isEmpty(list)) {
			if (ygDay != null) {
				list.add(ygDay);
			}
			if (thirdDay != null) {
				list.add(thirdDay);
			}
		} else {
			for (BiSupplierOrderDay o : list) {
				BiSupplierOrderDay tempDay = o.getSupplierId().compareTo(1L) == 0 ? ygDay : thirdDay;
				if (tempDay == null) {
					continue;
				}
				o.setTotalOrderCount(o.getTotalOrderCount() + tempDay.getTotalOrderCount());
				o.setTotalOrderPrice(o.getTotalOrderPrice().add(tempDay.getTotalOrderPrice()));
				o.setTotalUserCount(o.getTotalUserCount() + tempDay.getTotalUserCount());
				o.setPayOrderCount(o.getPayOrderCount() + tempDay.getPayOrderCount());
				o.setPayOrderPrice(o.getPayOrderPrice().add(tempDay.getPayOrderPrice()));
				o.setPayUserCount(o.getPayUserCount() + tempDay.getPayUserCount());
				o.setTotalCostPrice(o.getTotalCostPrice().add(tempDay.getTotalCostPrice()));
			}
		}
	}

	/**
	 * 计算毛利
	 *
	 * @param list
	 */
	private void doGrossMargin(List<BiSupplierOrderDay> list) {
		list.forEach(o -> {
			BigDecimal zero = new BigDecimal("0.00");
			if (o.getPayOrderPrice().compareTo(zero) > 0) {
				BigDecimal gg = (o.getPayOrderPrice().subtract(o.getTotalCostPrice())).divide(o.getPayOrderPrice(), 4, BigDecimal.ROUND_HALF_DOWN)
						.multiply(BigDecimal.valueOf(100));
				BigDecimal setScale = gg.setScale(2, BigDecimal.ROUND_HALF_DOWN);
				o.setGrossMargin(setScale);
			} else {
				o.setGrossMargin(zero);
			}
		});
	}

	private List<BiSupplierOrderDay> statisticsSupplierOrderByTimeV2(Date startDate, Date endDate,
																	 boolean currentOrderDay, boolean splitPlatform) {
		return biSupplierOrderDayMapper.
				executeOrderStatisticsBySupplierV2(startDate, endDate, currentOrderDay, splitPlatform);
	}

	@SuppressWarnings({"unused"})
	@Deprecated
	private List<BiSupplierOrderDay> statisticsSupplierOrderByTime(Date startDate, Date endDate, boolean currentOrderDay) {
		List<BiSupplierOrderDay> list = biSupplierOrderDayMapper.executeOrderStatisticsBySupplier(startDate, endDate, currentOrderDay);
		if (CollectionUtils.isEmpty(list)) {
			list = new ArrayList<>();
		}
		statisticsSupplierOrderByTotalPrice(startDate, endDate, currentOrderDay, list);
		List<BiSupplierOrderDay> grossProfit = biSupplierOrderDayMapper.executeOrderCostPriceBySupplier(startDate, endDate, currentOrderDay);
		if (CollectionUtils.isEmpty(grossProfit)) {
			return list;
		}
		Map<Long, List<BiSupplierOrderDay>> map1 = list.stream().collect(Collectors.groupingBy(BiSupplierOrderDay::getSupplierId));
		Map<Long, List<BiSupplierOrderDay>> map2 = grossProfit.stream().collect(Collectors.groupingBy(BiSupplierOrderDay::getSupplierId));
		if (MapUtils.isEmpty(map1)) {
			return list;
		}
		for (Map.Entry<Long, List<BiSupplierOrderDay>> entry : map1.entrySet()) {
			BiSupplierOrderDay bd1 = entry.getValue().get(0);
			if (map2 == null || CollectionUtils.isEmpty(map2.get(entry.getKey()))) {
				bd1.setGrossMargin(new BigDecimal("0.00"));
				bd1.setTotalCostPrice(new BigDecimal("0.00"));
			} else {
				BiSupplierOrderDay bd2 = map2.get(entry.getKey()).get(0);
				bd1.setGrossMargin(bd2.getGrossMargin());
				bd1.setTotalCostPrice(bd2.getTotalCostPrice());
			}
		}
		return list;
	}

	private void statisticsSupplierOrderByTotalPrice(Date startDate, Date endDate, boolean currentOrderDay, List<BiSupplierOrderDay> list) {
		// 指定时间创建的订单
		List<YgOrder> orderListByCreateTime = ygOrderService.findByCreateTimeHasDetail(startDate, endDate, null);
		Map<Long, BigDecimal> mapByCreateTime = statisticsSupplierOrderByDay(orderListByCreateTime);
		List<YgOrder> orderListByPaidTime = ygOrderService.findByPaidTimeHasDetail(startDate, endDate, null);
		if (CollectionUtils.isNotEmpty(orderListByPaidTime) && currentOrderDay) {
			orderListByPaidTime = orderListByPaidTime.stream().filter(o -> (o.getCreateTime().compareTo(startDate) >= 0 && o.getCreateTime().before(endDate)))
					.collect(Collectors.toList());
		}
		Map<Long, BigDecimal> mapByPaidTime = statisticsSupplierOrderByDay(orderListByPaidTime);
		for (BiSupplierOrderDay orderDay : list) {
			BigDecimal totalOrderPrice = mapByCreateTime.get(orderDay.getSupplierId()) == null ? ZERO : mapByCreateTime.get(orderDay.getSupplierId());
			orderDay.setTotalOrderPrice(totalOrderPrice);
			BigDecimal payOrderPrice = mapByPaidTime.get(orderDay.getSupplierId()) == null ? ZERO : mapByPaidTime.get(orderDay.getSupplierId());
			orderDay.setPayOrderPrice(payOrderPrice);
		}
	}

	private Map<Long, BigDecimal> statisticsSupplierOrderByDay(List<YgOrder> orderList) {
		Map<Long, BigDecimal> map = new HashMap<>(orderList.size());
		if (CollectionUtils.isEmpty(orderList)) {
			return map;
		}
		for (YgOrder order : orderList) {
			getOrderSharePrice(order);
			for (YgOrderDetail detail : order.getOrderDetail()) {
				BigDecimal totalPrice = map.get(detail.getSupplierId());
				if (totalPrice == null) {
					totalPrice = new BigDecimal("0.00");
				}
				totalPrice = totalPrice.add(detail.getOrderSharePrice());
				map.put(detail.getSupplierId(), totalPrice);
			}
		}
		return map;
	}

	private void getOrderSharePrice(YgOrder order) {
		List<YgOrderDetail> details = order.getOrderDetail();
		BigDecimal lastPrice = order.getTotalPrice();
		for (int i = 0; i < details.size(); i++) {
			YgOrderDetail detail = details.get(i);
			if (order.getProductPrice().compareTo(BigDecimal.ZERO) == 0) {
				detail.setOrderSharePrice(BigDecimal.ZERO);
				continue;
			}
			if (i == details.size() - 1) {
				detail.setOrderSharePrice(lastPrice);
			} else {
				BigDecimal price = detail.getSalePrice().multiply(new BigDecimal(detail.getQuantity())).divide(order.getProductPrice(), 4, BigDecimal.ROUND_HALF_DOWN)
						.multiply(order.getTotalPrice()).setScale(2, BigDecimal.ROUND_HALF_DOWN);
				detail.setOrderSharePrice(price);
				lastPrice = lastPrice.subtract(price);
			}

		}
		order.setOrderDetail(details);
	}

	@Override
	public Message supplierOrderReportByDay(Date startDate, Date endDate) {
		Date now = new Date();
		endDate = DateConvertUtils.getDateStart(endDate);
		List<BiSupplierOrderDay> list = new ArrayList<>();
		if (startDate.before(DateConvertUtils.getDateStart(now))) {
			// 包含今天前的每日各品牌数据
			List<BiSupplierOrderDay> historyList = biSupplierOrderDayMapper.selectSuper(null, null, startDate, endDate, null);
			if (CollectionUtils.isNotEmpty(historyList)) {
				list.addAll(historyList);
			}
		}
		if (endDate.after(DateConvertUtils.getDateStart(now))) {
			// 统计今天的各品牌数据
			List<BiSupplierOrderDay> currentList =
					this.statisticsSupplierOrderByTimeV2(DateConvertUtils.getDateStart(now), endDate,
							false, false);
			if (CollectionUtils.isNotEmpty(currentList)) {
				currentList.forEach(o -> o.setOrderDate(new Date()));
				list.addAll(currentList);
			}
		}
		if (CollectionUtils.isEmpty(list)) {
			return Message.success(list);
		}
		// 计算毛利
		doGrossMargin(list);
		Map<String, List<BiSupplierOrderDay>> map = list.stream().filter(o -> o.getSupplierId().compareTo(1L) != 0)
				.collect(Collectors.groupingBy(BiSupplierOrderDay::getSupplierName));
		String startFormat = DateConvertUtils.format(startDate);
		List<String> days = DateConvertUtils.diffDay(startFormat, DateConvertUtils.format(DateConvertUtils.addDay(endDate, -1)));
		days.add(startFormat);
		for (Map.Entry<String, List<BiSupplierOrderDay>> entry : map.entrySet()) {
			List<BiSupplierOrderDay> value = entry.getValue();
			for (String day : days) {
				boolean notExists = true;
				for (BiSupplierOrderDay orderDay : value) {
					if (day.equals(DateConvertUtils.format(orderDay.getOrderDate()))) {
						notExists = false;
						break;
					}
				}
				if (notExists) {
					Date orderDate = DateConvertUtils.parse(day, "yyyy-MM-dd");
					value.add(new BiSupplierOrderDay(orderDate, 0L, ZERO, 0L, 0L, ZERO, 0L, ZERO, ZERO, value.get(0).getSupplierId(), entry.getKey()));
				}
			}
			value.sort(Comparator.comparing(BiSupplierOrderDay::getOrderDate));
		}
		return Message.success(map);
	}

	@Override
	public Message supplierOrderReportByMonth(Date startDate, Date endDate) {
		List<BiSupplierOrderDay> list = supplierOrderByMonth(startDate, endDate);
		if (CollectionUtils.isEmpty(list)) {
			return Message.success(list);
		}
		doGrossMargin(list);
		Map<String, List<BiSupplierOrderDay>> map = list.stream().filter(o -> o.getSupplierId().compareTo(1L) != 0)
				.collect(Collectors.groupingBy(BiSupplierOrderDay::getSupplierName));
		String startFormat = DateConvertUtils.format(startDate, "yyyy-MM");
		List<String> months = DateConvertUtils.diffMonth(startFormat, DateConvertUtils.format(DateConvertUtils.addDay(endDate, -1), "yyyy-MM"));
		months.add(startFormat);
		for (Map.Entry<String, List<BiSupplierOrderDay>> entry : map.entrySet()) {
			List<BiSupplierOrderDay> value = entry.getValue();
			for (String month : months) {
				boolean notExists = true;
				for (BiSupplierOrderDay orderDay : value) {
					if (month.equals(orderDay.getMonth())) {
						notExists = false;
						break;
					}
				}
				if (notExists) {
					BiSupplierOrderDay orderDay = new BiSupplierOrderDay(null, 0L, ZERO, 0L, 0L, ZERO, 0L, ZERO, ZERO, value.get(0).getSupplierId(),
							entry.getKey());
					orderDay.setMonth(month);
					value.add(orderDay);
				}
			}
			value.sort((o1, o2) -> {
				Date month1 = DateConvertUtils.parse(o1.getMonth(), "yyyy-MM");
				Date month2 = DateConvertUtils.parse(o2.getMonth(), "yyyy-MM");
				return month1 == null || month2 == null ? 0 : month1.compareTo(month2);
			});
		}
		return Message.success(map);
	}

	private List<BiSupplierOrderDay> supplierOrderByMonth(Date startDate, Date endDate) {
		startDate = DateConvertUtils.getDateStart(startDate);
		endDate = DateConvertUtils.getDateStart(endDate);
		return biSupplierOrderDayMapper.selectSupplierOrderByMonth(startDate, endDate);
	}

	@Override
	public ResultSet<BiSupplierOrderDay> searchaByMonth(QueryInfo queryInfo, Date startDate, Date endDate) {
		startDate = DateConvertUtils.getDateStart(startDate);
		endDate = DateConvertUtils.getDateStart(endDate);
		List<BiSupplierOrderDay> list = biSupplierOrderDayMapper.selectSuperByMonth(queryInfo, startDate, endDate);
		doGrossMargin(list);
		int count = biSupplierOrderDayMapper.countSuperByMonth(startDate, endDate);
		return new ResultSet<>(count, list);
	}

	@Override
	public List<BiSupplierOrderDay> statisticsSupplierOrderByDay(Date startDate, Date endDate, boolean currentOrderDay,
																 boolean splitPlatform) {
		List<BiSupplierOrderDay> orderDayList = statisticsSupplierOrderByTimeV2(startDate, endDate,
				currentOrderDay, splitPlatform);
		orderDayList.forEach(o -> o.setOrderDate(startDate));
		doGrossMargin(orderDayList);
		return orderDayList;
	}

	@Override
	public Message resetSupplierReport(Date startDate, Date endDate) {
		this.deleteBetweenDate(startDate, endDate);
		this.addSupplierOrderDay(startDate, endDate);
		return Message.success(null);
	}

	@Override
	public ResultSet<BiSupplierOrderDay> searchSupplierOrderReportByMonth(QueryInfo queryInfo, Date startDate,
																		  Date endDate, String platformNo,
															   boolean groupSupplier, boolean splitYg) {
		if (startDate != null) {
			startDate = DateConvertUtils.getMonthStartDate(startDate);
		}
		if (endDate != null) {
			endDate = DateConvertUtils.addMonth(DateConvertUtils.getMonthStartDate(endDate), 1);
		}
		int total = biSupplierOrderDayMapper.countSupplierOrderReportByMonth(startDate, endDate, platformNo,
				ygSupplierId, groupSupplier, splitYg);
		if (total == 0) {
			return new ResultSet<>();
		}
		List<BiSupplierOrderDay> result = biSupplierOrderDayMapper.supplierOrderReportByMonth(queryInfo, startDate, endDate,
				platformNo, ygSupplierId, groupSupplier, splitYg);
		doGrossMargin(result);
		return new ResultSet<>(total, result);
	}

	private void addSupplierOrderDay(Date startDate, Date endDate) {
		List<BiSupplierOrderDay> biSupplierOrderDays = new ArrayList<>();
		Date maxDate = endDate;
		while (!startDate.before(maxDate)) {
			endDate = DateConvertUtils.addDay(startDate, 1);
			biSupplierOrderDays.addAll(this.statisticsSupplierOrderBySku(startDate, endDate));
			startDate = endDate;
		}
		this.saveBatch(biSupplierOrderDays);
	}

	private List<BiSupplierOrderDay> statisticsSupplierOrderBySku(Date startDate, Date endDate) {
		List<BiSupplierOrderDay> biSupplierOrderDays = biSupplierOrderDayMapper.executeOrderStatisticsBySku(startDate, endDate);
		biSupplierOrderDays.forEach(o -> o.setOrderDate(startDate));
		doGrossMargin(biSupplierOrderDays);
		return biSupplierOrderDays;
	}

	/**
	 * 逻辑删除指定时间内的数据
	 *
	 * @param startDate 开始日期
	 * @param endDate   结束日期
	 */
	private void deleteBetweenDate(Date startDate, Date endDate) {
		biSupplierOrderDayMapper.deleteBetweenDate(startDate, endDate);
	}

}
